home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / asmutil / disasm.zip / UASM.DOC < prev    next >
Encoding:
Text File  |  1988-06-03  |  24.4 KB  |  521 lines

  1.                                 UASM.DOC
  2.  
  3.         UASM  (for  Unassembler) consists of five files at this time:
  4.     UASM.DOC,  UASM-JMP.BAS,  UASM-INT.BAS,  UASM-STR.BAS  and  UASM-
  5.     DOS.MAC,  with  the purpose of converting the unassembled listing
  6.     of a .COM file from DEBUG into a .ASM file which can be  modified
  7.     and re-assembled with the Macro assembler.
  8.  
  9.     **************************** NOTICE *****************************
  10.  
  11.        USER SUPPORTED SOFTWARE  (With thanks to Andrew Flugelman)
  12.  
  13.     A limited license is granted to  all  users  of  these  programs,
  14.     to  make  and  distribute  copies  for other users subject to the
  15.     following conditions:
  16.  
  17.        1.  None of  the  notices  or  credits  are  to  be  bypassed,
  18.            altered, or removed.
  19.        2.  The programs are not to be distributed in  modified  form.
  20.            (Users are encouraged to distribute MERGE files.)
  21.        3.  No fee is  to  be  charged  (or  any  other  consideration
  22.            received) for copying or distributing the programs without
  23.            an express written agreement with White Crane Systems.
  24.  
  25.     ***************************************************************
  26.  
  27.                UASM - The White Crane Systems Unassembler
  28.  
  29.         If you are using these program  and  finding  them  of  value
  30.     please  send  a  cash  contribution  to  support their upkeep and
  31.     distribution.  Use the UASM  system  of  programs  to  unassemble
  32.     one average length .COM file, look over the results and calculate
  33.     how many hours this would have taken you  to  produce.   Multiply
  34.     this  by  the  minimum  wage,  contribute that amount and use the
  35.     program free thereafter.  If  that's  too  much  just  send  $20.
  36.     Supporters  will receive free notice of enhancements and updates.
  37.  
  38.         In any case you are encouraged to copy  and  distribute  UASM
  39.     to  your friends provided you do so free of charge and in unmodi-
  40.     fied form.
  41.                              Guy C. Gordon
  42.                           White Crane Systems
  43.                           3194 Friar Tuck Way
  44.                           Doraville, GA 30340
  45.  
  46.                               INTRODUCTION
  47.  
  48.         The strategy used in this system is  to  capture  the  output
  49.     of  DEBUG  and  run  it  through a series of BASIC programs, each
  50.     of which modifies one type of statement in  the  listing,  making
  51.     it  more like an .ASM source file.  This keeps each program short
  52.     and fast, and allows you to look over the  output  at  each  step
  53.     to  make  sure  no mistakes have been entered.  It also makes the
  54.     programs easy to understand and  improve  as  new  steps  can  be
  55.     added  without  interfering  with  the  first steps. Later in its
  56.     development UASM will combine these steps.   I  hope  that  users
  57.     of  these  programs  will  send  me  their improvements so that I
  58.     may add them to future releases.
  59.  
  60.         UASM-JMP takes captured unassembled code  from  DEBUG  (which
  61.     we  will  name  FILE.DB)  and  finds  all addresses referenced by
  62.     the various Jump, Call, and Loop instructions.  These  referenced
  63.     addresses  are  made  into  labels  of the form Lhhhh (where hhhh
  64.     is the hex address).  A  new  file  (FILE.JMP)  is  then  written
  65.     in  the  form  of  assembler  source  code.  All of the addresses
  66.     and hex opcodes in the left two  columns  of  the  DEBUG  listing
  67.     are  left  out.   Referenced  lines  are appropriately labeled as
  68.     Lhhhh:.  In addition, unconditional  program  transfers  such  as
  69.     JMP,  JMPS,  RET  and  IRET have blank lines inserted after them.
  70.     If the next line is not referenced  it  will  be  force  labeled,
  71.     and  a  warning  comment  will be appended.  The line after a RET
  72.     or IRET is most likely the  beginning  of  a  Procedure,  and  is
  73.     preceeded by three blank lines.
  74.  
  75.         UASM-INT  reads  FILE.JMP  and  writes  FILE.INT  in which it
  76.     has added Macro calls and comments explaining the various  Inter-
  77.     rupts.   The  macros,  symbols,  and  comments  are read from the
  78.     file UASM-DOS.MAC.  This file contains a table of  EQUates  which
  79.     define  the  symbols  for  the various DOS function calls and the
  80.     DOSCALL macro.  It is included in FILE.INT by means of an INCLUDE
  81.     directive.
  82.  
  83.         UASM-STR  reads  FILE.INT  and  writes FILE.STR.  Whenever it
  84.     encounters a DOSCALL PRINT$ hhhh it reads  the  string  beginning
  85.     at  hhhh  from  the original .COM file and prints it as a comment
  86.     beside the macro call.  It also generates a  Dhhhh:  DB  'string'
  87.     instruction  at  the  end  of  the  file.  Carriage Returns, Line
  88.     Feeds, TABs and ESCapes are  expressed  as  symbols.   All  other
  89.     non-printing characters are expressed as hex data bytes.  Because
  90.     this will not catch all text strings in the file,  you  are  also
  91.     allowed  to  specify ranges of DEBUG addresses in which  UASM-STR
  92.     is to find all the strings  it  can.   Whenever  the  code  loads
  93.     the  DX  register  with the address of one of these strings, that
  94.     address is converted to a label and the string is  added  to  the
  95.     line as a comment.
  96.  
  97.         From that point on, you must take over and supply the remain-
  98.     ing text strings and variables that are  addressed.   You  should
  99.     heavily  comment  the  code  as  you go through it and change the
  100.     labels that UASM has assigned into more meaningful  names.   This
  101.     is  best done with the global change command in your text editor.
  102.     I also recommend using the Macro CREF program to obtain  a  cross
  103.     reference map of the symbols.
  104.  
  105.         These  programs  are  by  no  means  infallible, and they can
  106.     no more read the programmers' mind than you or  I,  so  you  will
  107.     have  to  check  the output closely.  If you expect to simply run
  108.     UASM and be handed a usable source file you're going to be disap-
  109.     pointed.   On  the other hand, if you've ever tried to understand
  110.     a program from just a DEBUG listing you will be  pleasantly  sur-
  111.     prised.   UASM  will  aid you in studying other programs by doing
  112.     a lot of the dirty work for you,  but  if  you  don't  study  the
  113.     code  you  won't  get  usable  output.   For example an interrupt
  114.     handling subroutine will not  necessarily  be  assigned  a  label
  115.     by  UASM-JMP  since it is not accessed by a Jump but by an inter-
  116.     rupt.  Therefore if you find a DOSCALL SET$INT hhhh in the  UASM-
  117.     INT  output  you  must check to see if the label Lhhhh was gener-
  118.     ated.  If not will have to go back to the DEBUG  output  to  find
  119.     the routine at address hhhh and assign it a label of your own.
  120.  
  121.         At  present,  UASM-INT  only  keeps  track of the AX, AH, AL,
  122.     DX, and DL registers.  Future improvements will  involve  a  more
  123.     complete  (and  much more complicated) DOSCALL macro in the UASM-
  124.     DOS.MAC file and the proper  calling  of  it  by  UASM-INT.   For
  125.     now, keep a close eye on the interrupts.
  126.  
  127.         I  have  been  using  these  programs to unassemble DEBUG.COM
  128.     and COMMAND.COM.  When  I  have  them  sufficiently  commented  I
  129.     will  post them on the BBS's.  At present I use mainly the Multi-
  130.     Link BBS at (404) 252-9438.  It is my hope that  UASM  will  lead
  131.     to a whole library of well commented, "reverse engineered" source
  132.     code for the MS-DOS operating  system  and  utilities.   I  would
  133.     appreciate anyone else working on the same to upload your results
  134.     to the BBS.  Suggestions and improvements  are  welcome.   Please
  135.     post them on the MultiLink BBS or send them directly to:
  136.  
  137.                       Guy C. Gordon
  138.                 White Crane Systems
  139.                 3194 Friar Tuck Way
  140.                 Doraville, GA 30340
  141.                          OPERATING INSTRUCTIONS
  142.                                  -DEBUG-
  143.  
  144.         As an example, we will unassemble a fictitious file, FILE.COM
  145.     A>debug file.com
  146.     -r
  147.     .....CX=1780 ...            ;file length in hex bytes
  148.     -d 100 l 1780                       ;display entire file
  149.  
  150.         In  the listing that follows you should be able to spot ASCII
  151.     text and any regular binary tables.   Write  down  the  beginning
  152.     and  ending  addresses  of these, as we do not want to unassemble
  153.     them, but we will want a printed copy.  Our aim is to put togeth-
  154.     er  a  list  of  all  blocks of code to be unassembled and string
  155.     addresses for UASM-STR.  Look  at  the  code  before  each  block
  156.     of  text.   Usually  it  will  be preceded by a hex C3 which is a
  157.     RET instruction, but there may be a  JMP,  JMPS,  IRET,  or  RETF
  158.     instead.   This  is  the  last  instruction we want to unassemble
  159.     in the block of code preceding the  text.   Take  your  time  and
  160.     go  through  the  entire  file, unassembling code and making sure
  161.     that the output looks reasonable.
  162.  
  163.         Reasonable code contains such things as CALL or Jump instruc-
  164.     tions  to  nearby  addresses,  INT  21  instructions and multiple
  165.     operations on single registers.  It does not contain DB  instruc-
  166.     tions or very many 00 bytes.  Also the ASCII display of a section
  167.     of code will look totally random, with  about  50%  of  it  being
  168.     displayable  characters.   (The  rest  will  be  periods.)  Peter
  169.     Norton has given a good demonstration of this  in  chapter  6  of
  170.     "Inside  the  IBM-PC".   One warning--the DEBUG unassembler tends
  171.     to lock into phase with the correct code,  which  is  very  nice,
  172.     but  be  certain  that  the  beginning  few instructions are also
  173.     in phase.  Sections of code that are in phase will contain  Jumps
  174.     and  CALLs  to  other  sections,  thus telling you where to start
  175.     unassembling.
  176.  
  177.         At the end of this investigation of the .COM file you  should
  178.     have  a  list  of  the  starting  and ending addresses of all the
  179.     code blocks and all the string blocks.   The  next  step  depends
  180.     upon  whether  you  have  DOS  2.0  or not.  It is much easier if
  181.     you have 2.0, or can to this  part  on  a  friend's  machine  who
  182.     has  it.   This  is  because under DOS 2.0 we can pipe the output
  183.     of DEBUG into a file thus  capturing  the  unassembled  code  for
  184.     input  to  UASM-JMP.   Under  DOS version 1. we must modify DEBUG
  185.     (using DEBUG of course) to get it to write the file we need.
  186.  
  187.                         DEBUG - 2.0 Instructions
  188.  
  189.         Create a file, FILE.IN, with  the  following  DEBUG  instruc-
  190.     tions:
  191.  
  192.     u addr 1 addr 2                     ;addresses of blocks of
  193.     u addr 3 addr 4                     ; code to unassemble
  194.     u addr 5 addr 6                     ; from our initial investiga-
  195.     tion
  196.     q                           ;Quit instruction at end
  197.  
  198.         Now we can run DEBUG and pipe the output to a disk file
  199.  
  200.     DEBUG FILE.COM <FILE.IN >FILE.DB
  201.  
  202.         FILE.DB is the input for UASM-JMP.
  203.  
  204.  
  205.                         DEBUG - 1.1 Instructions
  206.  
  207.         While it is quite easy to capture the output of  DEBUG  under
  208.     DOS  2.0  since  we  can pip it to a file, under earlier versions
  209.     of DOS we have no such option.  However, DEBUG is an exceptional-
  210.     ly  powerful  program,  and  already  contains the code necessary
  211.     to write a disk file with the Write command.  We  will  use  this
  212.     to capture the Unassembled code.
  213.  
  214.         If we unassemble and examine DEBUG, we can find the following
  215.     subroutine:
  216.  
  217.     02C8:02C0   PUSH    AX              ;save registers
  218.                 PUSH    DX
  219.                 AND     AL,7F           ;insure character is ASCII
  220.                 XCHG    DX,AX           ;put character in DL
  221.                 MOV     AH,02           ;DOS Function  2  to  display
  222.     DL
  223.                 INT     21
  224.                 POP     DX              ;restore registers
  225.                 POP     AX
  226.                 RET                     ;return
  227.  
  228.         As  it turns out, DEBUG does all of its screen output through
  229.     this subroutine.  Thus we can modify  just  this  subroutine  and
  230.     capture  each  character  as  it  is  displayed.  What we will do
  231.     with it is write it out to an unused  portion  of  memory.   From
  232.     there  we  can  write  all  the  output to a file using the Write
  233.     command.
  234.  
  235.         Our subroutine to store character AL  in  consecutive  memory
  236.     locations  will  be very small--about 20 bytes.  We'll need some-
  237.     place to put it.  For DEBUG 1.07 I  chose  to  put  it  inside  a
  238.     string  which  is  only  printed once--the message "DEBUG version
  239.     1.07" located at 0102.  Here is the subroutine:
  240.  
  241.     02C8:0102   DW      3300            ;pointer to memory
  242.                 PUSH    DI              ;save index register
  243.                 SEG     CS              ;offset form code, not ES
  244.                 MOV     DI,[0102]       ;get pointer
  245.                 SEG     CS              ;
  246.                 STOSB                   ;store char in AL into memory
  247.                 SEG     CS              ;
  248.                 MOV     [0102],DI       ;store incremented pointer
  249.                 POP     DI              ;restore register
  250.                 XCHG    DX,AX           ;complete  the   instructions
  251.     that
  252.                 MOV     AH,02           ;  CALL  to  this routine re-
  253.     placed
  254.                 RET                     ;Return to Display routine
  255.  
  256.         We can store this subroutine over the string with  the  Enter
  257.     command.  (here  02C8 is the base address where DEBUG is loaded):
  258.  
  259.     E 2C8:102 00 33 57 2E 8B 3E 02 01 2E AA 2E 89  3E  02  01  5F  92
  260.               B4 02 C3
  261.  
  262.     We  can  check  that  this  was entered correctly by Unassembling
  263.     it:
  264.  
  265.     U 2C8:104           ;you should see the subroutine listed above.
  266.  
  267.         The choice of memory location is up  to  you.   3300  Is  the
  268.     value  I  used  while  unassembling  DEBUG.   It should be larger
  269.     than the sum of the sizes (in bytes) of  DEBUG  and  the  program
  270.     you  are  unassembling.  To have this subroutine called each time
  271.     DEBUG writes a character, we insert a subroutine Call:
  272.  
  273.     E 2C8:2C4 E8 3D FE          ;Call 0104
  274.  
  275.     This puts a CALL 0104 in place  of  XCHG  DX,AX  and  MOV  AH,02.
  276.     That  is  why  we  perform those instructions before returning to
  277.     the display routine.  The very  next  charter  printed  by  DEBUG
  278.     after  you  Enter  the  above  command will be stored in location
  279.     2C8:3300 as well as displayed on the screen.
  280.  
  281.         Immediately after entering the  CALL  instruction  above  you
  282.     should  begin  the  Unassemble  commands that you determined will
  283.     give you all the code for the program.
  284.  
  285.     U 100 4D5
  286.     U 6b0 799
  287.     etc.
  288.     D 2C8:102 103               ;This displays  the  pointer  to  the
  289.     end of text
  290.         B3 D9           ;This means we filled memory to D9B3
  291.                         ;(remember the 8088 stores words backwards)
  292.     H D9B3 3300         ;Hex arithmetic
  293.         0CB3 A6B3       ;  D9B3 - 3300 = A6B3
  294.     R CX
  295.         CX=1748
  296.         :A6B3           ;load  CX  register  with  number of bytes to
  297.     write
  298.     N FILE.DB           ;name the output file
  299.     W 2C8:3300          ;start writing at 3300 off. from DEBUG base
  300.        Writing A6B3 bytes
  301.     E 2C8:102 00 33             ;reset pointer if out of space
  302.  
  303.         Remember, you can only write text to memory up  to  2C8:FFFF.
  304.     If  you  exceed  that  you  will write over DEBUG at 2C8:0000 and
  305.     will probably have to re-boot.  If FILE.COM is too big  to  Unas-
  306.     semble  in  one  pass  you'll  have to do it in pieces and append
  307.     them together with your text  editor.   For  this  reason  it  is
  308.     a  good  idea  to  modify  and save a copy of DEBUG under another
  309.     name such as UDEBUG.  If you need to perform any other operations
  310.     with  a  modified  DEBUG  that  you do not want written to memory
  311.     you can restore DEBUG to normal operation with:
  312.  
  313.     E 2C8:2C4 92 B4 02  ;restores XCHG DX,AX and MOV AH,02
  314.  
  315.         Now text edit FILE.DB and remove any  extraneous  lines  such
  316.     as  debug  prompts  that might have been displayed.  If there are
  317.     any TABs in FILE.DB they will confuse UASM-JMP  and  the  others.
  318.     DEBUG  1.1  appears  to  put  a  TAB after each instruction while
  319.     version 2.0 does not.  I always use the  text  editor  to  change
  320.     all  TABs  to the appropriate number of spaces.  (Users of PMATE,
  321.     use the YF command.)
  322.  
  323.         Any of the memory addresses above may vary with your  operat-
  324.     ing  system  and  DEBUG  version.   The  values given are for the
  325.     Victor 9000, MS-DOS 1.25a, and  DEBUG  1.07.   The  Base  Segment
  326.     where  DEBUG  is loaded (2C8 above) will depend upon your machine
  327.     and operating system, and is  found  by  using  DEBUG  to  Search
  328.     for itself in memory.  The display subroutine (2C0 above) depends
  329.     upon your DEBUG  version  number.   The  same  subroutine  occurs
  330.     at  2B5 in the DEBUG that comes with PC-DOS 1.10, and will appear
  331.     near these locations in any  other  version  1  DEBUGs.   If  you
  332.     store  the  capture  subroutine at some other place in memory you
  333.     need to change the two [0102] references and the  CALL  0104  in-
  334.     struction.
  335.  
  336.                          UASM-JMP  Instructions
  337.  
  338.          Run UASM-JMP as you would any basic program.  It will prompt
  339.     you for the name of  input  and  output  files.     Respond  with
  340.     FILE.DB  ,which  we  created  above,  and  B:FILE.JMP for output.
  341.     If file extensions are not provided, .DB and .JMP will be assumed
  342.     for  input  and  output  respectively.  Also the output file name
  343.     will default to the input file name. I highly  recommend  putting
  344.     these  files  on  separate drives if you don't have a fixed disk.
  345.     This will speed up the program and save wear on your floppies.
  346.  
  347.         UASM-JMP will make two passes through  the  input  file.   On
  348.     the  first  pass  it  will  build a list of all referenced lines.
  349.     It then sorts this list (shell sort), eliminates  duplicate  ref-
  350.     erences,  and  on  the second pass, labels all of the references.
  351.     The output will be displayed on your screen as  well  as  written
  352.     out on the second pass.
  353.  
  354.         If  the  program  finds a Jump or CALL to an address not con-
  355.     tained in the file you will get the  message  "WARNING!  No  code
  356.     for  this  label".   This  most likely means you missed the block
  357.     of code starting at address hhhh and  will  have  to  add  it  to
  358.     the  input  file for DEBUG.  The statement after an unconditional
  359.     program transfer (JMP or RET) is  always  labeled.   The  message
  360.     "WARNING!  This  label  not  referenced"  means  that there is no
  361.     Jump or CALL to this label.  It might be  an  interrupt  handler,
  362.     or  it  might  just  be  left over code in a modified program.  A
  363.     large number of these errors might indicate  that  they  are  ac-
  364.     cessed  by  an  address  table.   Both  of the above errors might
  365.     occur if you miss a block of code, unassemble  a  data  area,  or
  366.     the code modifies itself.
  367.  
  368.                          UASM-INT  Instructions
  369.  
  370.         To run UASM-INT you must also have the data file UASM-DOS.MAC
  371.     on the default drive.  UASM-INT will  prompt  you  for  an  input
  372.     and  output  file  names.   If  extensions are not provided, .JMP
  373.     and .INT will be  assumed  for  input  and  output  respectively.
  374.     The  program  then  loads  the  symbol  table  contained in UASM-
  375.     DOS.MAC.   While  reading  through  FILE.JMP,  whenever  UASM-INT
  376.     encounters  an  INT  instruction  it  adds  a Macro call, Symbols
  377.     for the DOS function calls, and Comments  from  the  UASM-DOS.MAC
  378.     file.   These  lines  will also be displayed on the screen as the
  379.     program progresses.  Note that  the  DOSCALL  Macro  is  inserted
  380.     in  the  text,  but  the  INT  instruction is not deleted.  After
  381.     you have checked the code you must delete the  INT  and  any  MOV
  382.     instructions that will be duplicated by the Macro.
  383.  
  384.                           UASM-STR Instructions
  385.  
  386.         To  run UASM-STR you must have the original FILE.COM or other
  387.     binary file on disk.  The program will prompt you for the  input,
  388.     output,  and  binary  file  names.   These  will default to .INT,
  389.     .STR and .COM if no other extension  is  given.   As  usual,  the
  390.     input  file  name will be used as a default if you do not specify
  391.     the others, and you should put the output  file  on  a  different
  392.     floppy drive than the input file.
  393.  
  394.         You  will  then  be  prompted  for  any string area addresses
  395.     that you may have found  while  examining  FILE.COM  with  DEBUG.
  396.     You  may  enter  an  address  range (hhhh kkkk) or the address of
  397.     a single string (hhhh) on each line.  (Up  to  ten  lines)   Each
  398.     address  must  be  a  four  digit hex offset (taken directly from
  399.     DEBUG).  Upon receiving a blank line as input, the  program  will
  400.     find  all  strings  terminated  with  a  $  starting at the first
  401.     address in a range  and  continue  finding  multiple  strings  to
  402.     the  second  address  if  present.   If a single address is given
  403.     on a line a single string will be  read.   Each  string  is  dis-
  404.     played as it is found.
  405.  
  406.         Following  this  the  program  reads  through  FILE.INT.  For
  407.     each "DOSCALL PRINT$   hhhh"  encountered  it  reads  the  string
  408.     from  FILE.COM  at  the  specified  location (taking into account
  409.     the 100H byte program prefix) and prints that string as a comment
  410.     next  to  the  Macro.   Also, each time the DX register is loaded
  411.     with the address of a string, that string is shown  next  to  the
  412.     code.   At  the  end  of  the file, UASM-INT will append a number
  413.     of EQUates and Data statements and define  the  string  variables
  414.     with  names  Dhhhh.   Non-printing  characters are converted into
  415.     hex bytes.  CR, LF, TAB, ESC, and $ are defined as symbols.
  416.  
  417.                  SAMPLE OUTPUT - Excerpts from DEBUG.STR
  418.  
  419. INCLUDE UASM-DOS.MAC
  420. .RADIX  16
  421.  
  422. START:  JMPS    L011D
  423.  
  424. L011D:  MOV     SP,1822
  425.         MOV     [1897],AL
  426.         MOV     DX,0102
  427.         MOV     AH,09
  428.         INT     21
  429.  
  430. DOSCALL PRINT$,D0102       ;CR,LF,'DEBUG-86  version 1.07',CR,LF,$
  431.         MOV     AX,2522
  432.         MOV     DX,01E6
  433.         INT     21
  434.  
  435. DOSCALL SET$INT     01E6   ; Set interrupt vector (AL=INT, DS:DX=VECTOR)
  436.  
  437.         MOV     AL,23
  438.         MOV     DX,01EB
  439.         INT     21
  440.  
  441. DOSCALL SET$INT     01EB   ; Set interrupt vector (AL=INT, DS:DX=VECTOR)
  442.  
  443.         MOV     DX,CS
  444.         ADD     DX,01AB
  445.         MOV     AH,26
  446.         INT     21
  447.  
  448. DOSCALL BUILD$PS    01AB      ; Create new program  segment  (DX=SEGMENT)
  449.  
  450.         MOV     AX,DX
  451.         MOV     DI,1832
  452.         STOSW
  453.         MOV     DX,0080
  454.         MOV     AH,1A
  455.         INT     21
  456.  
  457. DOSCALL SET$DTA     0080      ; Set Disk Transfer Address to DX
  458.  
  459.         MOV     AX,[0006]
  460.         MOV     BX,AX
  461.         CMP     AX,FFF0
  462.         PUSH    CS
  463.         POP     DS
  464.         ADD     [0008],BX
  465.         MOV     DI,005C
  466.         MOV     SI,0081
  467.         MOV     AX,2901
  468.  
  469.         INT     21
  470.  
  471. DOSCALL PARSE$         ; Parse Filespec (SI -> LINE, DI -> FCB, AL=CODE)
  472.  
  473.         CALL    L0917
  474.         PUSH    CS
  475.         POP     ES
  476.         CMP     B,[005D],20
  477.         JZ      L01B5
  478.         JMPS    L01B5
  479.  
  480. L01E3:  JMP     L04CB
  481.  
  482. L01E6:   MOV      DX,167A             ;WARNING! This label not referenced
  483.         MOV     DS,AX
  484.         MOV     SS,AX
  485.         MOV     SP,1822
  486.         MOV     AH,09
  487.         INT     21
  488.  
  489. DOSCALL PRINT$            ; Display string @DX till terminator
  490.  
  491.         JMPS    L01B5
  492.  
  493. L01FD:  MOV     AH,0A
  494.         MOV     DX,1844
  495.         INT     21
  496.  
  497. DOSCALL INSTR$      1844  ; Input keyboard string (DX -> size,cnt,buffer)
  498.  
  499.         MOV     SI,1846
  500. ;END CODE
  501. .RADIX  16
  502. CR      EQU     0D
  503. LF      EQU     0A
  504. TAB     EQU     09
  505. ESC     EQU     1B
  506. $       EQU     24
  507. D167A   DB      CR,LF,'Program terminated normally',CR,LF,$
  508. D169A   DB      'Invalid drive or file name',CR,LF,$
  509. D16B7   DB      'File not found',CR,LF,$
  510. D16C8   DB      'No room in disk directory',CR,LF,$
  511. D16E4   DB      'Insufficient space on disk',CR,LF,$
  512. D1701   DB      'Disk$'
  513. D1706   DB      'Write protect$'
  514. D1714   DB      ' error reading drive A',CR,LF,$
  515. D172D   DB      'readwritInsufficient memory',CR,LF,$
  516. D174B   DB      '^ Error',CR,8A,' ',88,'Error in EXE/HEX file',CR,LF,$
  517. D176E   DB      'EXE/HEX file cannot be written',CR,LF,$
  518. D178F   DB      'Writing $'
  519. D1798   DB      ' bytes',CR,LF,$
  520. D0102   DB      CR,LF,'DEBUG-86  version 1.07',CR,LF,$
  521.